#include "compiler.h"
#include "helpers/vector.h"
#include "helpers/buffer.h"
#include <string.h>
#include <ctype.h>

// 宏函数
#define LEX_GETC_IF(buffer, c, exp)     \
    for (c = peekc(); exp; c = peekc()) \
    {                                   \
        buffer_write(buffer, c);        \
        nextc();                        \
    }

static struct lex_process *lex_process;
static struct token tmp_token;

struct token *read_next_token();

static char peekc()
{
    return lex_process->function->peek_char(lex_process);
}

static char nextc()
{
    char c = lex_process->function->next_char(lex_process);
    lex_process->pos.col += 1; // 增加列号
    if (c == '\n')             // 如果字符是换行符
    {
        lex_process->pos.line += 1; // 行号+1
        lex_process->pos.col = 1;   // 列号归1
    }

    return c;
}

static void pushc(char c)
{
    lex_process->function->push_char(lex_process, c);
}

static struct position lex_file_position()
{
    return lex_process->pos;
}

struct token *token_create(struct token *_token)
{
    memcpy(&tmp_token, _token, sizeof(struct token));
    tmp_token.pos = lex_file_position();
    return &tmp_token;
}

static struct token *lexer_last_token()
{
    return vector_back_or_null(lex_process->token_vec);
}

static struct token *handle_whitespace()
{
    struct token *last_token = lexer_last_token();
    if (last_token)
    {
        last_token->whitespace = true;
    }
    nextc();
    return read_next_token();
}

const char *read_number_str()
{
    const char *num = NULL;
    struct buffer *buffer = buffer_create();
    char c = peekc();
    LEX_GETC_IF(buffer, c, (c >= '0' && c <= '9'));
    buffer_write(buffer, 0x00);
    return buffer_ptr(buffer);
}

unsigned long long read_number()
{
    const char *s = read_number_str();
    return atoll(s);
}

struct token *token_make_number_for_value(unsigned long number)
{
    return token_create(&(struct token){.type = TOKEN_TYPE_NUMBER, .llnum = number});
}

struct token *token_make_number()
{
    return token_make_number_for_value(read_number());
}

// 获取字符串令牌
struct token *token_make_string(char start_delim, char end_delim)
{
    struct buffer *buffer = buffer_create();

    char c = nextc();
    // 词法分析中采用peekc()向前查看，但并未移动指针，此时c='"'，需要再nextc()
    // 若不nextc(),c == end_delim，会跳过该 '"' ，将字符串中字母作为其他token进行识别
    c = nextc();
    for (; c != end_delim && c != EOF; c = nextc())
    {
        if (c == '\\')
        {
            // TODO 处理"\"转义字符
            continue;
        }
        buffer_write(buffer, c);
    }
    buffer_write(buffer, 0x00);
    return token_create(&(struct token){.type = TOKEN_TYPE_STRING, .sval = buffer_ptr(buffer)});
};

// 单个使用的操作符
static bool op_treated_as_one(char op)
{
    return op == '(' || op == '[' || op == '*' || op == ',' || op == '.' || op == '?';
}

// 可以两两连用的操作符
static bool is_single_operator(char op)
{
    return op == '+' ||
           op == '-' ||
           op == '*' ||
           op == '<' ||
           op == '>' ||
           op == '^' ||
           op == '%' ||
           op == '!' ||
           op == '=' ||
           op == '~' ||
           op == '|' ||
           op == '&' ||
           op == '(' ||
           op == '[' ||
           op == ',' ||
           op == '.' ||
           op == '?' ||
           op == '/';
}

// 运算符是否有效
bool op_valid(const char *op)
{
    return S_EQ(op, "+") ||
           S_EQ(op, "-") ||
           S_EQ(op, "*") ||
           S_EQ(op, "<") ||
           S_EQ(op, ">") ||
           S_EQ(op, "^") ||
           S_EQ(op, "%") ||
           S_EQ(op, "!") ||
           S_EQ(op, "=") ||
           S_EQ(op, "~") ||
           S_EQ(op, "|") ||
           S_EQ(op, "&") ||
           S_EQ(op, "(") ||
           S_EQ(op, "[") ||
           S_EQ(op, ",") ||
           S_EQ(op, ".") ||
           S_EQ(op, "?") ||
           S_EQ(op, "/") ||
           S_EQ(op, "+=") ||
           S_EQ(op, "-=") ||
           S_EQ(op, "*=") ||
           S_EQ(op, "/=") ||
           S_EQ(op, ">>") ||
           S_EQ(op, "<<") ||
           S_EQ(op, ">=") ||
           S_EQ(op, "<=") ||
           S_EQ(op, "||") ||
           S_EQ(op, "&&") ||
           S_EQ(op, "++") ||
           S_EQ(op, "--") ||
           S_EQ(op, "!=") ||
           S_EQ(op, "==") ||
           S_EQ(op, "->") ||
           S_EQ(op, "...");
}

// 获取操作符函数
const char *read_op()
{
    bool single_operator = true;
    char op = nextc();
    struct buffer *buffer = buffer_create();
    buffer_write(buffer, op);
    // 如果op为++类连续操作
    if (!op_treated_as_one(op))
    {
        op = peekc();
        if (is_single_operator(op))
        {
            buffer_write(buffer, op);
            op = nextc();
            single_operator = false;
        }
    }
    // 向缓冲区写入终止符0x00并获其中数据
    buffer_write(buffer, 0x00);
    char *ptr = buffer_ptr(buffer);
    if (!single_operator)
    {
        // 如果两种运算符不能连用则将缓冲区最后一个字符pushc()
        if (!op_valid(ptr))
        {
            const char *data = buffer_ptr(buffer);
            int len = buffer->len;
            for (int i = len - 1; i >= 1; i--)
            {
                if (data[i] == 0x00)
                {
                    continue;
                }
                pushc(data[i]);
            }
            ptr[1] = 0x00;
        }
    }
    else if (!op_valid(ptr))
    {
        compile_error(lex_process->compiler, "这个 %s 操作符不存在\n", ptr);
    }
    return ptr;
}

// 出现新的语句初始符，创建新的缓冲区
static void lex_new_expression()
{
    lex_process->current_expression_count++;
    if (lex_process->current_expression_count == 1)
    {
        lex_process->parentheses_buffer = buffer_create();
    }
}

// 出现语句结束符
static void lex_finish_expression()
{
    lex_process->current_expression_count--;
    if (lex_process->current_expression_count < 0)
    {
        compile_error(lex_process->compiler, "缺少右括号\n");
    }
}
// 当前词法分析是否在（）中
bool lex_is_in_expression()
{
    return lex_process->current_expression_count > 0;
}

// 判断是否为关键字
bool is_keyword(const char *str)
{
    return S_EQ(str, "char") ||
           S_EQ(str, "int") ||
           S_EQ(str, "long") ||
           S_EQ(str, "float") ||
           S_EQ(str, "double") ||
           S_EQ(str, "if") ||
           S_EQ(str, "else") ||
           S_EQ(str, "for") ||
           S_EQ(str, "while") ||
           S_EQ(str, "break") ||
           S_EQ(str, "continue") ||
           S_EQ(str, "return") ||
           S_EQ(str, "void") ||
           S_EQ(str, "struct") ||
           S_EQ(str, "union") ||
           S_EQ(str, "enum") ||
           S_EQ(str, "typedef") ||
           S_EQ(str, "static");
}

// 获取操作符令牌
static struct token *token_make_operator_or_string()
{
    char op = peekc();
    // #include <stdio.h>
    if (op == '<')
    {
        struct token *last_token = lexer_last_token();
        if (token_is_keyword(last_token, "include"))
        {
            return token_make_string('<', '>');
        }
    }
    struct token *token = token_create(&(struct token){.type = TOEKN_TYPE_OPERATOR,
                                                       .sval = read_op()});
    if (op == '(')
    {
        lex_new_expression();
    }
    return token;
}

// 获取结束符令牌
struct token *token_make_symbol()
{

    char c = nextc();
    if (c == ')')
    {
        lex_finish_expression();
    }
    struct token *token = token_create(&(struct token){.type = TOKEN_TYPE_SYMBOL,
                                                       .cval = c});
    return token;
}

// 获取标识符、关键字令牌
static struct token *token_make_identifier_or_keyword()
{
    struct buffer *buffer = buffer_create();
    char c = 0;
    LEX_GETC_IF(buffer, c, (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')

    buffer_write(buffer, 0x00);
    // 判断是否是关键字或者标识符
    if (is_keyword(buffer_ptr(buffer)))
    {
        return token_create(&(struct token){.type = TOKEN_TYPE_KEYWORD,
                                            .sval = buffer_ptr(buffer)});
    }
    return token_create(&(struct token){.type = TOKEN_TYPE_IDENTIFIER, .sval = buffer_ptr(buffer)});
}

struct token *read_special_token()
{
    char c = peekc();
    // 如果字符为字母、数字、下划线
    if (isalpha(c) || c == '_')
    {
        return token_make_identifier_or_keyword();
    }
    return NULL;
}

// 获取行令牌
struct token *token_make_newLine()
{
    nextc();
    return token_create(&(struct token){.type = TOKEN_TYPE_NEWLINE, .cval = '\n'});
}

// 获取单行注释令牌
struct token *token_make_one_line_comment()
{
    struct buffer *buffer = buffer_create();
    char c = 0;
    // 读取的是一整行，到\n结束或者是结束符EOF
    LEX_GETC_IF(buffer, c, c != '\n' && c != EOF);
    return token_create(&(struct token){.type = TOKEN_TYPE_COMMENT, .sval = buffer_ptr(buffer)});
}

/**
 * 获取多行注释令牌
 */
struct token *token_make_mutiline_comment()
{
    struct buffer *buffer = buffer_create();
    char c = 0;
    while (1)
    {
        LEX_GETC_IF(buffer, c, c != '*' && c != EOF);
        if (c == EOF)
        {
            compile_error(lex_process->compiler, "多行注释没有结束\n");
        }
        else if (c == '*')
        {
            // 如果为行注释的*则跳过当前*
            nextc();
            if (peekc() == '/')
            {
                nextc();
                break;
            }
        }
    }
    return token_create(&(struct token){.type = TOKEN_TYPE_COMMENT, .sval = buffer_ptr(buffer)});
}

// 获取注释令牌
struct token *handle_comment_token()
{
    char c = peekc();
    if (c == '/')
    {
        nextc();
        if (peekc() == '/')
        {
            nextc();
            return token_make_one_line_comment();
        }
        else if (peekc() == '*')
        {
            nextc();
            return token_make_mutiline_comment();
        }

        // 如果都不是，可能/是除号
        pushc('/');
        return token_make_operator_or_string();
    }
    return NULL;
}

// 获取\转义字符
char lex_get_escaped_char(char c)
{
    switch (c)
    {
    case 'a':
        return '\a';
    case 'b':
        return '\b';
    case 'f':
        return '\f';
    case 'n':
        return '\n';
    case 'r':
        return '\r';
    case 't':
        return '\t';
    case 'v':
        return '\v';
    case '\\':
        return '\\';
    case '\'':
        return '\'';
    case '\"':
        return '\"';
    case '?':
        return '\?';
    case '0':
        return '\0';
    default:
        return c;
    }
}

// 弹出vector的最后一个
void lexer_pop_token()
{
    vector_pop(lex_process->token_vec);
}

// 判断是否是16进制字符
bool is_hex_char(char c)
{
    c = tolower(c);
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}

// 读取16进制字符串
const char *read_hex_number_str()
{
    struct buffer *buffer = buffer_create();
    char c = peekc();
    LEX_GETC_IF(buffer, c, is_hex_char(c));
    buffer_write(buffer, 0x00);
    return buffer_ptr(buffer);
}

// 将16进制字符串转换为数字
struct token *token_make_special_number_hexadecimal()
{
    // 跳过x
    nextc();
    unsigned long number = 0;
    const char *number_str = read_hex_number_str();
    // 将字符串转换为数字
    number = strtol(number_str, 0, 16);
    return token_make_number_for_value(number);
}

// 判断二进制字符是否合法
void lexer_validate_binary_string(const char *str)
{
    size_t len = strlen(str);
    for (int i = 0; i < len; i++)
    {
        if (str[i] != '0' && str[i] != '1')
        {
            compile_error(lex_process->compiler, "非法二进制字符串\n");
        }
    }
}

// 将2进制字符串转换为数字
struct token *token_make_special_number_binary()
{
    // 跳过x
    nextc();
    unsigned long number = 0;
    const char *number_str = read_number_str();
    lexer_validate_binary_string(number_str);
    // 将字符串转换为数字
    number = strtol(number_str, 0, 2);
    return token_make_number_for_value(number);
}

// 获取特殊数字
struct token *token_make_special_number()
{
    struct token *token = NULL;
    // 如果当前字符串不是特殊数字则是一个关键字或者标识符
    struct token *last_token = lexer_last_token();
    if (!last_token || !(last_token->type == TOKEN_TYPE_NUMBER && last_token->llnum == 0))
    {
        return token_make_identifier_or_keyword();
    }

    // 弹出0x12的0
    lexer_pop_token();

    char c = peekc();
    if (c == 'x')
    {
        token = token_make_special_number_hexadecimal();
    }
    else if (c == 'b')
    {
        token = token_make_special_number_binary();
    }
    return token;
}

// 获取''引号令牌
struct token *token_make_quote()
{
    // c目前是'的前一个字符，需要两次next才能获取到''中的值
    nextc();
    char c = nextc();
    // c为\的转义字符
    if (c == '\\')
    {
        c = nextc();
        // 获取转义字符
        c = lex_get_escaped_char(c);
    }
    // ''中只有一个字符或者转义字符，如果获取完值后不是右'则报错
    if (nextc() != '\'')
    {
        compile_error(lex_process->compiler, "''中的字符只能为1个\n");
    }
    return token_create(&(struct token){.type = TOKEN_TYPE_NUMBER, .cval = c});
};

struct token *read_next_token()
{
    struct token *token = NULL;
    char c = peekc();
    // 如果当前c是/，优先考虑是注释的情况
    token = handle_comment_token();
    if (token)
    {
        return token;
    }
    switch (c)
    {
    NUMBER_CASE:
        token = token_make_number();
        break;
    OPERATOR_CASE_EXCLUDING_DIVISION:
        token = token_make_operator_or_string();
        break;
    SYMBOL_CASE:
        token = token_make_symbol();
        break;
    case 'b':
    case 'x':
        token = token_make_special_number();
        break;
    case '"':
        token = token_make_string('"', '"');
        break;
    case '\'':
        token = token_make_quote();
        break;
    case ' ':
    case '\t':
        token = handle_whitespace();
        break;
    case '\n':
        token = token_make_newLine();
        break;
    case EOF:
        // 词法分析结束
        break;
    default:
        token = read_special_token();
        // 未知字符
        if (!token)
        {
            compile_error(lex_process->compiler, "不能识别的字符\n");
        }
        break;
    }
    return token;
}

int lex(struct lex_process *process)
{
    process->current_expression_count = 0;
    process->parentheses_buffer = NULL;
    lex_process = process;
    process->pos.filename = process->compiler->cfile.abs_path;

    struct token *token = read_next_token();
    while (token)
    {
        vector_push(process->token_vec, token);
        token = read_next_token();
    }

    return LEXICAL_ANALYSIS_ALL_OK;
}